/* Die Klasse Datum alle Werte, die ein Datum ausmachen. Ausserdem 
 * bietet die Klasse die Moeglichkeit, bestimmte Berechnungen mit
 * Datumswerten vorzunehmen.
 * 
 * Datei: Datum.java                   Autor:   Antonia Wagner 
 * Datum: 23.11.11                     Version: 0.3 
 * 
 * Historie: 23.11.11 v0.1 von Autor erstellt, Tag, Monat, Jahr, sowie
 *                         Stunde, Minute, Sekunde und die 
 *                         entsprechenden Get- und Set-Methoden 
 *                         implementiert, die Berechnungsmethoden istVor,
 *                         istNach und berechneDatum implementiert.
 *           01.12.11 v0.2 Einfuegen einer Zuordnungstabelle fuer die
 *                         Monate und die jeweilige Anzahl an Tagen und
 *                         die Anpassung der jeweiligen Methoden auf 
 *                         die neue Art von Berechnung
 *           10.12.11 v0.3 Fehler in der Datumsberechnung behoben                       
 */

package personenverwaltung;

import GUI.Dashboard;
import basis.lokal.Lokalisierung;
import basis.lokal.Sprachen;

public class Datum
{
  private static int ALTER_VOLLJAEHRIGKEIT = 18;

  private int tag;
  private int monat;
  private int jahr;
  private int stunde;
  private int minute;
  private int sekunde;
  private Lokalisierung lokal;


  /**
   * 
   * @param tag
   *          des Datums
   * @param monat
   *          des Datums
   * @param jahr
   *          des Datums
   */
  public Datum (int tag, int monat, int jahr)
  {
    setzeMonat (monat);
    setzeJahr (jahr);
    setzeTag (tag);

    /*
     * Sprache abfragen und speichern
     */
    Sprachen sprache = Dashboard.verwendeteSprache ();
    setzeSprache (sprache.toString ());
  }


  /**
   * 
   * @param tag
   *          des Datums
   * @param monat
   *          des Datums
   * @param jahr
   *          des Datums
   * @param stunde
   *          des Datums
   * @param minute
   *          des Datums
   * @param sekunde
   *          des Datums
   */
  public Datum (int tag, int monat, int jahr, int stunde, int minute,
      int sekunde)
  {
    this (tag, monat, jahr);
    setzeStunde (stunde);
    setzeMinute (minute);
    setzeSekunde (sekunde);
  }


  /**
   * 
   * @return den Tag zum Datum
   */
  public int gibTag ()
  {
    return tag;
  }


  /**
   * 
   * @param tag
   *          den Tag zum Datum
   */
  public void setzeTag (int tag)
  {
    int anzahlTage = gibAnzahlTageFuerMonat (monat);

    /*
     * Schaltjahr behandeln
     */
    if (istSchaltjahr (jahr))
    {
      anzahlTage++;
    }
    /*
     * Pruefen, ob ein Tagesdatum im fuer den Monat gueltigen Intervall
     * angegeben wurde
     */
    if ((tag <= anzahlTage) && (tag > 0))
    {
      this.tag = tag;
    }
    else
    {
      throw new UngueltigesDatumAusnahme (
          lokal.gibUebersetzung ("Ungueltiger Tag"));
    }

  }


  /**
   * 
   * @return den Monat zum Datum
   */
  public int gibMonat ()
  {
    return monat;
  }


  /**
   * 
   * @param monat
   *          den Monat zum Datum
   */
  public void setzeMonat (int monat)
  {
    if ((monat < 13) && (monat > 0))
    {
      this.monat = monat;
    }
    else
    {
      throw new UngueltigesDatumAusnahme (
          lokal.gibUebersetzung ("Ungueltiger Monat"));
    }
  }


  /**
   * 
   * @return das Jahr zum Datum
   */
  public int gibJahr ()
  {
    return jahr;
  }


  /**
   * 
   * @param jahr
   *          das Jahr zum Datum
   */
  public void setzeJahr (int jahr)
  {
    if (jahr > 0)
    {
      this.jahr = jahr;
    }
    else
    {
      if (lokal != null)
      {
        throw new UngueltigesDatumAusnahme (
            lokal.gibUebersetzung ("Ungueltiges Jahr"));
      }
      else
      {
        throw new UngueltigesDatumAusnahme ("Ungueltiges Jahr");
      }
    }
  }


  /**
   * 
   * @return die Stunde zum Datum
   */
  public int gibStunde ()
  {
    return stunde;
  }


  /**
   * 
   * @param stunde
   *          die Stunde zum Datum
   */
  public void setzeStunde (int stunde)
  {
    if ((stunde < 25) && (stunde >= 0))
    {
      this.stunde = stunde;
    }
    else
    {
      throw new UngueltigesDatumAusnahme (
          lokal.gibUebersetzung ("Ungueltige Stunde"));
    }
  }


  /**
   * 
   * @return die Minute zum Datum
   */
  public int gibMinute ()
  {
    return minute;
  }


  /**
   * 
   * @param minute
   *          die Minute zum Datum
   */
  public void setzeMinute (int minute)
  {
    if ((minute < 60) && (minute >= 0))
    {
      this.minute = minute;
    }
    else
    {
      throw new UngueltigesDatumAusnahme (
          lokal.gibUebersetzung ("Ungueltige Minute"));
    }
  }


  /**
   * 
   * @return die Sekunde zum Datum
   */
  public int gibSekunde ()
  {

    return sekunde;
  }


  /**
   * 
   * @param sekunde
   *          die Sekunde zum Datum
   */
  public void setzeSekunde (int sekunde)
  {
    if ((sekunde < 60) && (sekunde >= 0))
    {
      this.sekunde = sekunde;
    }
    else
    {
      throw new UngueltigesDatumAusnahme (
          lokal.gibUebersetzung ("Ungueltige Sekunde"));
    }
  }


  /**
   * 
   * @param datum
   *          das darauf ueberprueft werden soll, ob es vor dem Datum
   *          liegt, bei dem der Aufruf stattfindet
   * @return ob das uebergebene Datum vor dem Datum liegt, bei dem der
   *         Aufruf stattfindet
   */
  public boolean istVor (Datum datum)
  {

    if (jahr < datum.gibJahr ())
    {
      return true;
    }
    else
    {
      if (monat < datum.gibMonat ())
      {
        return true;
      }
      else
      {
        if (tag < datum.gibTag ())
        {
          return true;
        }
        else
        {
          return false;
        }
      }
    }
  }


  /**
   * 
   * @param datum
   *          das darauf ueberprueft werden soll, ob es nach dem Datum
   *          liegt, bei dem der Aufruf stattfindet
   * @return ob das uebergebene Datum nach dem Datum liegt, bei dem der
   *         Aufruf stattfindet
   */
  public boolean istNach (Datum datum)
  {
    if (jahr > datum.gibJahr ())
    {
      return true;
    }
    else
    {
      if (monat > datum.gibMonat ())
      {
        return true;
      }
      else
      {
        if (tag > datum.gibTag ())
        {
          return true;
        }
        else
        {
          return false;
        }
      }
    }
  }


  /**
   * berechnet die Gleichheit von zwei Datums-Werten
   * 
   * @param datum
   *          das Datum, mit dem der Vergleich stattfinden soll
   * @return ob die Datums-Werte gleich sind oder nicht
   */
  public boolean istGleich (Datum datum)
  {
    boolean gleichesJahr = (jahr == datum.gibJahr ());
    boolean gleicherMonat = (monat == datum.gibMonat ());
    boolean gleicherTag = (tag == datum.gibTag ());

    if (gleicherTag && gleicherMonat && gleichesJahr)
    {
      return true;
    }
    else
    {
      return false;
    }

  }


  public String toString ()
  {
    return tag + "." + monat + "." + jahr;
  }


  public static boolean istSchaltjahr (int jahr)
  {
    if ((jahr % 4 == 0) && ((jahr % 100 != 0) || (jahr % 400 == 0)))
    {
      return true;
    }
    else
    {
      return false;
    }
  }


  /**
   * Berechnet einen Datumswert
   * 
   * @param anfangsDatum
   *          das Datum, an dem die Berechnung beginnen soll
   * @param anzahlTagePlus
   *          die Anzahl der Tage, die zum anfangsDatum addiert werden
   *          sollen
   * 
   * @return das Ergebnis der Berechnung als Datumswert
   */
  public static Datum berechneDatum (Datum anfangsDatum,
      int anzahlTagePlus)
  {
    int tagStart = anfangsDatum.gibTag ();
    int monat = anfangsDatum.gibMonat ();
    int jahr = anfangsDatum.gibJahr ();
    int anzahlTage = gibAnzahlTageFuerMonat (monat);

    /*
     * Schaltjahr behandeln
     */
    if ((monat) == 2 && (istSchaltjahr (jahr)))
    {
      anzahlTage++;
    }

    /*
     * Ueberpruefen, ob die Berechnung einen langen Zeitraum umfasst und
     * rekursiv erfolgen muss
     */
    if (anzahlTagePlus >= anzahlTage)
    {
      /*
       * Den Monat eins hoch setzen
       */
      Datum datum = berechneMonatPlusEins (anfangsDatum);

      /*
       * Die bereits beruecksichtigten Tage von der Addition abziehen
       */
      anzahlTagePlus = (anzahlTagePlus - anzahlTage);

      /*
       * Die Methode mit den neuen Werten erneut aufrufen
       */
      return berechneDatum (datum, anzahlTagePlus);
    }

    /*
     * den Tag berechnen
     */
    int tag = ( (tagStart + anzahlTagePlus) % anzahlTage);

    /*
     * letzten Tag des Monats behandeln
     */
    if (tag == 0)
    {
      tag = anzahlTage;
    }

    /*
     * Monats- und Jahreswechsel behandeln
     */
    Datum datum = new Datum (tag, monat, jahr);
    if (tagStart > tag)
    {
      datum = berechneMonatPlusEins (datum);
    }

    return datum;
  }


  /**
   * Berechnet, ob eine Person volljaegrig ist und stuetzt sich dabei
   * auf das uebergebene Geburts- und das Tagesdatum
   * 
   * @param geburtsdatum
   *          der Person, fuer die Volljaehrigkeit berechnet werden soll
   * 
   * @return ob die Person volljaehrig ist oder nicht
   */
  public static boolean istVolljaehrig (Datum geburtsdatum)
  {
    boolean istVolljaehrig = false;
    Datum tagesdatum = AktuellesDatum.gibAktuellesDatum ();

    /*
     * Das Referenzdatum ist das Datum, das auf den Tag genau 18 Jahre
     * her ist. Fuer alle Laender, in denen man mit 18 volljaehrig ist,
     * kann so die Volljaehrigkeit berechnet werden. Gilt eine anderes
     * Alter, muesste die Konstante angepasst werden.
     */
    Datum referenzdatum = tagesdatum;

    int jahr = tagesdatum.gibJahr ();
    jahr = jahr - ALTER_VOLLJAEHRIGKEIT;
    referenzdatum.setzeJahr (jahr);

    /*
     * Prueft, ob das Referenzdatum gleich oder nach dem Geburtsdatum
     * liegt, wenn ja, ist die Person volljaehrig
     */
    if ((referenzdatum.istNach (geburtsdatum))
        || (referenzdatum.istGleich (geburtsdatum)))
    {
      istVolljaehrig = true;
    }

    return istVolljaehrig;

  }


  /*
   * Berechnet den uebergebenen Monat plus eins, ein Jahreswechsel wird
   * beruecksichtigt und das berechnete Datum zurueckgeliefert
   */
  private static Datum berechneMonatPlusEins (Datum datum)
  {
    int monat = datum.gibMonat ();
    int jahr = datum.gibJahr ();

    if (monat != 12)
    {
      monat++;
    }
    else
    {
      monat = 1;
      jahr++;
    }

    datum.setzeMonat (monat);
    datum.setzeJahr (jahr);

    return datum;
  }


  /*
   * erzeugt eine Zuordnungstabelle Monat -> Anzahl Tage
   */
  private static int gibAnzahlTageFuerMonat (int monat)
  {
	if((monat < 0) || (monat > 12))
	{
	  throw new UngueltigesDatumAusnahme ();
	}
    int tagesTabelle[] = new int[13];
    tagesTabelle[1] = 31;
    tagesTabelle[2] = 28;
    tagesTabelle[3] = 31;
    tagesTabelle[4] = 30;
    tagesTabelle[5] = 31;
    tagesTabelle[6] = 30;
    tagesTabelle[7] = 31;
    tagesTabelle[8] = 31;
    tagesTabelle[9] = 30;
    tagesTabelle[10] = 31;
    tagesTabelle[11] = 30;
    tagesTabelle[12] = 31;

    int anzahlTage = tagesTabelle[monat];

    return anzahlTage;
  }


  /**
   * @param sprache
   *          die verwendet werden soll
   */
  public void setzeSprache (String sprache)
  {
    lokal = new Sprachverwaltung (sprache).gibLokalisierung ();
  }

}
